package xyz.zhzby.cyzx.judge.core;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.LineIterator;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.IOException;

/**
 * @author zby
 * @date 2022/02/04
 * @Description 比较器，用于比对用户输出结果和标准结果.
 */
@Component
@Slf4j
public class Comparator {

    /**
     * @Param [standardOutputFilePath, outputFilePath] [标准输出文件路径, 用户输出文件路径]
     * @Return boolean [用户输出和标准输出是否相同]
     * @Author zby
     * @Date 2022/02/04
     * @Description 获取用户输出和标准输出的比对结果.
     */
    public boolean isOutputTheSame(String standardOutputFilePath, String outputFilePath) throws IOException {
        File stdFile = new File(standardOutputFilePath);
        File file = new File(outputFilePath);

        LineIterator stdFileItr = FileUtils.lineIterator(stdFile, "UTF-8");
        LineIterator fileItr = FileUtils.lineIterator(file, "UTF-8");
        boolean isFileOutputTheSame = isFileOutputTheSame(stdFileItr, fileItr);

        LineIterator.closeQuietly(stdFileItr);
        LineIterator.closeQuietly(fileItr);
        return isFileOutputTheSame;
    }

    /**
     * @Param [stdFileItr, fileItr] [标准输出文件的迭代器, 用户输出文件的迭代器]
     * @Return boolean [标准输出和用户输出是否相同]
     * @Author zby
     * @Date 2022/02/04
     * @Description 比对标准输出和用户输出是否相同.
     */
    private boolean isFileOutputTheSame(LineIterator stdFileItr, LineIterator fileItr) {
        try {
            while (stdFileItr.hasNext() && fileItr.hasNext()) {
                String stdLine = stdFileItr.nextLine();
                String line = fileItr.nextLine();

                if (!isLineOutputTheSame(stdLine, line)) {
                    return false;
                }
            }
            while (stdFileItr.hasNext()) {
                String line = stdFileItr.nextLine();
                if (!isLineEmpty(line, 0)) {
                    return false;
                }
            }
            while (fileItr.hasNext()) {
                String line = fileItr.nextLine();
                if (!isLineEmpty(line, 0)) {
                    return false;
                }
            }
        } catch (OutOfMemoryError ex) {
            log.error(ex.getMessage());
            return false;
        }
        return true;
    }

    /**
     * @Param [stdLine, line] [标准输出中的某一行, 用户输出中的某一行]
     * @Return boolean [某行的标准输出和用户输出是否相同]
     * @Author zby
     * @Date 2022/02/04
     * @Description 比对某行的标准输出和用户输出(忽略行尾空格).
     */
    private boolean isLineOutputTheSame(String stdLine, String line) {
        int i = 0, j = 0;
        for (; i < stdLine.length() && j < line.length(); ++i, ++j) {
            if (stdLine.charAt(i) != line.charAt(j)) {
                if (stdLine.charAt(i) == '\n') {
                    return isLineEmpty(line, j);
                } else if (line.charAt(j) == '\n') {
                    return isLineEmpty(stdLine, i);
                }
                return false;
            }
        }
        while (i < stdLine.length()) {
            if (!isLineEmpty(stdLine, i)) {
                return false;
            }
            ++i;
        }
        while (j < line.length()) {
            if (!isLineEmpty(line, j)) {
                return false;
            }
            ++j;
        }
        return true;
    }

    /**
     * @Param [line, startIndex] [某行文件内容, 开始检查位置的索引]
     * @Return boolean [该行内容中是否只包含空格和换行符]
     * @Author zby
     * @Date 2022/02/04
     * @Description 忽略文件结尾的空行与空格.
     */
    private boolean isLineEmpty(String line, int startIndex) {
        for (int i = startIndex; i < line.length(); ++i) {
            if (!(line.charAt(i) == ' ' || line.charAt(i) == '\n')) {
                return false;
            }
        }
        return true;
    }

    /**
     * @Param [standardOutputFilePath] [标准输出文件路径]
     * @Return boolean [标准输出文件内容]
     * @Author zby
     * @Date 2022/02/08
     * @Description 获取用户输入的标准输出文件内容
     */
    public String getOutput(String standardOutputFilePath) throws IOException {
        StringBuilder result = new StringBuilder();
        File stdFile = new File(standardOutputFilePath);
        LineIterator stdFileItr = FileUtils.lineIterator(stdFile, "UTF-8");
        while (stdFileItr.hasNext()) {
            String stdLine = stdFileItr.nextLine();
            result.append(stdLine).append("\n");
        }
        return result.toString();
    }

}
